Author Id: 28815 Author Name: Razhier Post Content: Lo primero, un saludo a todo el foro. Éste es mi primer mensaje y mi primera aportación al RH, espero que os sirva de ayuda. El caso, que llevo tiempo buscando la forma de añadir Pokémon errantes al Esmeralda (en español, es la ROM que utilizo). He buscado en este foro y en foro de PokemonCommunity, y no he conseguido encontrar nada. Así que empecé a investigar la forma en que aparecían Latios y Latias en el juego. A continuación dejo los pasos que he seguido durante mi investigación, por si a alguien le interesa o le pueda servir de ayuda. Si sólo quieres saber cómo se meten pokémon errantes, sáltate este paso. [SPOILER="Desarrollo de la investigación. NO ES NECESARIO LEER"]En mi búsqueda, encontré la dirección del script de cuando te pasas la liga y tu madre te pregunta de qué color era el pokémon de la tele, si rojo o azul. Concretamente, el script es éste: [SPOILER="Script de la madre"]#org 0x29793E lockall checkgender compare LASTRESULT 0x0 if 0x1 call 0x8297AC2 compare LASTRESULT 0x1 if 0x1 call 0x8297AD2 compare 0x8008 0x0 if 0x1 call 0x8297B54 compare 0x8008 0x1 if 0x1 call 0x8297B5F applymovement 0x8009 0x82763A2 waitmovement 0x0 sound 0x15 applymovement 0x8009 0x827639C waitmovement 0x0 applymovement 0x8009 0x827639E waitmovement 0x0 pause 0x14 compare 0x8008 0x0 if 0x1 call 0x8297AE2 compare 0x8008 0x1 if 0x1 call 0x8297AED msgbox 0x81F87BF MSG_KEEPOPEN '"PAPÁ: ¿Eh?\p¡Pero si es mi [player..." giveitem 0x109 0x1 MSG_OBTAIN msgbox 0x81F8896 MSG_KEEPOPEN '"PAPÁ: ¿Un TICKET para el ferry?\pS..." closeonkeypress pause 0x14 compare 0x8008 0x0 if 0x1 call 0x8297AF8 compare 0x8008 0x1 if 0x1 call 0x8297B0D msgbox 0x81F88FF MSG_KEEPOPEN '"Mejor vuelvo al GIMNASIO de PETALI..." closeonkeypress compare 0x8008 0x0 if 0x1 call 0x8297B22 compare 0x8008 0x1 if 0x1 call 0x8297B3B sound 0x8 hidesprite 0x8009 setflag 0x123 pause 0x1E compare 0x8008 0x0 if 0x1 call 0x8297B94 compare 0x8008 0x1 if 0x1 call 0x8297BA9 pause 0x14 msgbox 0x81F8965 MSG_KEEPOPEN '"MAMÁ: Este padre tuyo[.]\pCuando p..." closeonkeypress setflag 0x8BD special 0x1F6 pause 0x3C compare 0x8008 0x0 if 0x1 call 0x8297BBE compare 0x8008 0x1 if 0x1 call 0x8297BC9 msgbox 0x81F8A08 MSG_KEEPOPEN '"MAMÁ: ¿Un especial informativo?" closeonkeypress compare 0x8008 0x0 if 0x1 call 0x8297B6A compare 0x8008 0x1 if 0x1 call 0x8297B7F msgbox 0x81F8A28 MSG_KEEPOPEN '"¡Interrumpimos la programación par..." closeonkeypress clearflag 0x8BD setflag 0xFF special 0x41 compare 0x8008 0x0 if 0x1 call 0x8297BD4 compare 0x8008 0x1 if 0x1 call 0x8297BE9 msgbox 0x81F8B40 MSG_KEEPOPEN '"MAMÁ: [player], ¿has oído eso?\p¿D..." multichoice 0x16 0x8 0x6C 0x1 copyvar 0x8004 LASTRESULT special 0x12B copyvar 0x40D5 LASTRESULT msgbox 0x81F8B93 MSG_KEEPOPEN '"MAMÁ: ¡Ver para creer!\n¡Aún hay P..." closeonkeypress setvar 0x4082 0x4 setvar 0x408C 0x4 releaseall end '--------------- #org 0x297AC2 setvar 0x8008 0x0 setvar 0x8009 0x5 setvar 0x800A 0x1 return '--------------- #org 0x297AD2 setvar 0x8008 0x1 setvar 0x8009 0x5 setvar 0x800A 0x1 return '--------------- #org 0x297B54 applymovement MOVE_PLAYER 0x8297C12 waitmovement 0x0 return '--------------- #org 0x297B5F applymovement MOVE_PLAYER 0x8297C1D waitmovement 0x0 return '--------------- #org 0x297AE2 applymovement 0x8009 0x8297BFE waitmovement 0x0 return '--------------- #org 0x297AED applymovement 0x8009 0x8297C01 waitmovement 0x0 return '--------------- #org 0x297AF8 applymovement 0x800A 0x82977D5 waitmovement 0x0 applymovement 0x8009 0x8297C04 waitmovement 0x0 return '--------------- #org 0x297B0D applymovement 0x800A 0x82977DD waitmovement 0x0 applymovement 0x8009 0x8297C06 waitmovement 0x0 return '--------------- #org 0x297B22 applymovement MOVE_PLAYER 0x8297C18 applymovement 0x800A 0x8297C18 applymovement 0x8009 0x8297C08 waitmovement 0x0 return '--------------- #org 0x297B3B applymovement MOVE_PLAYER 0x8297C18 applymovement 0x800A 0x8297C18 applymovement 0x8009 0x8297C0D waitmovement 0x0 return '--------------- #org 0x297B94 applymovement 0x800A 0x82977E5 waitmovement 0x0 applymovement MOVE_PLAYER 0x82763A8 waitmovement 0x0 return '--------------- #org 0x297BA9 applymovement 0x800A 0x82977E7 waitmovement 0x0 applymovement MOVE_PLAYER 0x82763AC waitmovement 0x0 return '--------------- #org 0x297BBE applymovement 0x800A 0x82977E9 waitmovement 0x0 return '--------------- #org 0x297BC9 applymovement 0x800A 0x82977F2 waitmovement 0x0 return '--------------- #org 0x297B6A applymovement MOVE_PLAYER 0x8297C23 waitmovement 0x0 applymovement 0x800A 0x82763A8 waitmovement 0x0 return '--------------- #org 0x297B7F applymovement MOVE_PLAYER 0x8297C2A waitmovement 0x0 applymovement 0x800A 0x82763AC waitmovement 0x0 return '--------------- #org 0x297BD4 applymovement 0x800A 0x82977FB waitmovement 0x0 applymovement MOVE_PLAYER 0x82763AC waitmovement 0x0 return '--------------- #org 0x297BE9 applymovement 0x800A 0x82977FF waitmovement 0x0 applymovement MOVE_PLAYER 0x82763A8 waitmovement 0x0 return '--------- ' Strings '--------- #org 0x1F87BF = PAPÁ: ¿Eh?\p¡Pero si es mi [player]!\pHace un siglo que no te veo[.]\n¡Si pareces mucho más fuerte!\pÉsa es la impresión que das, ¡pero\ntu padre aún puede dar guerra!\pAh, sí, tengo algo para ti.\nTe lo envía un tal SR. ARENQUE. #org 0x1F8896 = PAPÁ: ¿Un TICKET para el ferry?\pSi recuerdo bien, los puertos donde\natraca son CIUDAD PORTUAL y CALAGUA. #org 0x1F88FF = Mejor vuelvo al GIMNASIO de PETALIA.\pCariño, gracias por ocuparte\nde la casa mientras yo estoy fuera. #org 0x1F8965 = MAMÁ: Este padre tuyo[.]\pCuando por fin viene un poco a casa,\nsólo se le ocurre hablar de POKéMON.\pDebería relajarse un poco y quedarse\nmás tiempo aquí tranquilito[.] #org 0x1F8A08 = MAMÁ: ¿Un especial informativo? #org 0x1F8A28 = ¡Interrumpimos la programación para\ntraerles las últimas noticias!\pHay noticias confusas sobre supuestos\navistamientos de un POKéMON azzzrt[.]\lvolando en distintos puntos de HOENN.\pActualmente se desconoce la identidad\ndel POKéMON.\pY ahora les dejamos con la programación\nhabitual. #org 0x1F8B40 = MAMÁ: [player], ¿has oído eso?\p¿De qué color ha dicho el de\nla tele que era ese POKéMON? #org 0x1F8B93 = MAMÁ: ¡Ver para creer!\n¡Aún hay POKéMON desconocidos! '----------- ' Movements '----------- #org 0x2763A2 #raw 0x3E 'Face Player #raw 0xFE 'End of Movements #org 0x27639C #raw 0x56 'Exclamation Mark (!) #raw 0xFE 'End of Movements #org 0x27639E #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0xFE 'End of Movements #org 0x297C12 #raw 0x14 'Delay5 #raw 0x8 'Step Down (Normal) #raw 0x8 'Step Down (Normal) #raw 0x8 'Step Down (Normal) #raw 0x27 'Step on the Spot Left (Fastest) #raw 0xFE 'End of Movements #org 0x297C1D #raw 0x14 'Delay5 #raw 0x8 'Step Down (Normal) #raw 0x8 'Step Down (Normal) #raw 0x8 'Step Down (Normal) #raw 0x28 'Step on the Spot Right (Fastest) #raw 0xFE 'End of Movements #org 0x297BFE #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0xFE 'End of Movements #org 0x297C01 #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0xFE 'End of Movements #org 0x2977D5 #raw 0x9 'Step Up (Normal) #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0x8 'Step Down (Normal) #raw 0x28 'Step on the Spot Right (Fastest) #raw 0xFE 'End of Movements #org 0x297C04 #raw 0x2 'Face Left #raw 0xFE 'End of Movements #org 0x2977DD #raw 0x9 'Step Up (Normal) #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0x8 'Step Down (Normal) #raw 0x27 'Step on the Spot Left (Fastest) #raw 0xFE 'End of Movements #org 0x297C06 #raw 0x3 'Face Right #raw 0xFE 'End of Movements #org 0x297C18 #raw 0x13 'Delay4 #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x25 'Step on the Spot Down (Fastest) #raw 0xFE 'End of Movements #org 0x297C08 #raw 0x8 'Step Down (Normal) #raw 0xB 'Step Right (Normal) #raw 0x8 'Step Down (Normal) #raw 0x13 'Delay4 #raw 0xFE 'End of Movements #org 0x297C0D #raw 0x8 'Step Down (Normal) #raw 0xA 'Step Left (Normal) #raw 0x8 'Step Down (Normal) #raw 0x13 'Delay4 #raw 0xFE 'End of Movements #org 0x2977E5 #raw 0xB 'Step Right (Normal) #raw 0xFE 'End of Movements #org 0x2763A8 #raw 0x27 'Step on the Spot Left (Fastest) #raw 0xFE 'End of Movements #org 0x2977E7 #raw 0xA 'Step Left (Normal) #raw 0xFE 'End of Movements #org 0x2763AC #raw 0x28 'Step on the Spot Right (Fastest) #raw 0xFE 'End of Movements #org 0x2977E9 #raw 0x27 'Step on the Spot Left (Fastest) #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x28 'Step on the Spot Right (Fastest) #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0xFE 'End of Movements #org 0x2977F2 #raw 0x28 'Step on the Spot Right (Fastest) #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0x27 'Step on the Spot Left (Fastest) #raw 0x14 'Delay5 #raw 0x14 'Delay5 #raw 0xFE 'End of Movements #org 0x297C23 #raw 0x9 'Step Up (Normal) #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0x26 'Step on the Spot Up (Fastest) #raw 0xFE 'End of Movements #org 0x297C2A #raw 0x9 'Step Up (Normal) #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0x26 'Step on the Spot Up (Fastest) #raw 0xFE 'End of Movements #org 0x2977FB #raw 0x9 'Step Up (Normal) #raw 0xA 'Step Left (Normal) #raw 0xA 'Step Left (Normal) #raw 0xFE 'End of Movements #org 0x2977FF #raw 0x9 'Step Up (Normal) #raw 0xB 'Step Right (Normal) #raw 0xB 'Step Right (Normal) #raw 0xFE 'End of Movements[/SPOILER] A nosotros nos interesa esta parte: multichoice 0x16 0x8 0x6C 0x1 copyvar 0x8004 LASTRESULT special 0x12B copyvar 0x40D5 LASTRESULT El special 0x12B tiene como variable de entrada la 0x8004. Lo que hace el special es lo siguiente: si 0x8004 es igual a 0, el pokémon errante que aparece es Latias; si es igual a 1, aparece Latios (por lo que he probado, cualquier valor distinto de 0 hace que aparezca Latios). La variable 0x40D5 no nos interesa, lo que hace es guardar el valor que hemos escogido para más tarde, en la isla del sur, que aparezca el pokémon que no hayamos elegido. El special 0x12B nos lleva a la dirección 0x8161961 y ejecuta el código en ASM que se encuentra allí. Pensé que la información del pokémon que nos aparece se guardaba en alguna parte de ese código, pero he estado buscando y no he encontrado nada (aunque tampoco sé como funciona el código). El código en cuestión es éste: [SPOILER="Imagen"] [IMG]http://s12.postimg.org/873b3tbkd/Hx_D.png[/IMG] [/SPOILER] Como no encontré nada buscando en el interior de la ROM, pasé a buscar en la memoria RAM. Para eso, hay que usar el buscador de cheats del emulador VBA (Ctrl + C). El valor de Latias en hexadecimal es 0x197, así que mi idea fue ejecutar el siguiente script: #org @inicio setvar 0x8004 0x0 special 0x12B end Que hace que aparezca Latias. Después de activar el special, busqué en el buscador de cheats el valor 0197, y me apareció la siguiente dirección: [SPOILER="Imagen"] [IMG]http://s12.postimg.org/a3zkp0lal/buscadorcheats.png[/IMG] [/SPOILER] Si abrimos el Tools > Memory Viewer, y nos vamos a esa dirección… [SPOILER="Imagen"] [IMG]http://s21.postimg.org/d88tcby1j/valores.png[/IMG] [/SPOILER] Parece ser que esos números tienen que ver con el pokémon errante que nos aparece. Algunos se pueden deducir a primera vista, otros he tenido que investigarlos un poco: Azul: número del pokémon errante invertido (Latias: 197, que invertido es 97 01) Verde: vitalidad actual. Cuando hieres a un pokémon errante y se escapa, la próxima vez que te lo encuentras sigue con la misma vida. Pues parece ser que es aquí donde se guarda ese valor (en HEX, por supuesto). Amarillo: nivel del pokémon, 28 en hex es 40 en decimal. Marrón: el estado del pokémon, que también se guarda de un combate a otro. Naranja: disponibilidad del pokémon (1 = vivo y salvaje, 0 = capturado o debilitado) Rojo: información encriptada que definen los valores iniciales, la naturaleza y posiblemente el género. Visto esto, mi primera idea fue bien simple, sustituir el número 0197 por el valor del nuevo pokémon. Después de investigar un poco acerca de las flags y las variables noté que la memoria donde se aloja la información del pokémon errante coincide con la memoria usada para las variables, es decir, que los pokémon errantes se guardan en variables. Las variables son: - Variable del pokémon: Esmeralda 0x4F24; RF 0x506C - Variable de la vitalidad: Esmeralda 0x4F25; RF 0x506D - Variable del nivel y estado: Esmeralda 0x4F26; RF 0x506E - Variable de la disponibilidad (0x100 = disponible, 0x0 = no disponible) = Esmeralda 0x5F29; FR 0x5071 Así que en teoría podríamos elegir al pokémon errante sólo editando las variables de antes con "setvar". En mi caso empecé probando con un Raikou, cuyo valor es 00F3. Ejecutando el script: #org @inicio special 0x12B setvar 0x4F24 0xF3 end Debería de aparecernos un Raikou errante. [SPOILER="Imagen"] [IMG]http://s30.postimg.org/7029vp2ld/valores3.png[/IMG] [/SPOILER] Efectivamente, nuestro script ha sustituido el 0197 por nuestro 00F3 que le habíamos dicho. Entonces… ¿Debería de aparecernos un Raikou errante? Vamos a consultar en la pokédex… (Nota: para facilitar el proceso, antes programé un "wildbattle" contra un Raikou para que me saliera en la pokédex, y que después me diera una masterball): [SPOILER="Imagen"] [IMG]http://s11.postimg.org/hgm0r9sgz/Raikou.png[/IMG] [/SPOILER] Efectivamente aparece el área de Raikou en la pokédex, y además va cambiando cada vez que nos movemos. Pero y si lo buscamos, ¿que nos encontramos? [SPOILER="Imagen"] [IMG]http://s28.postimg.org/k76yxmqst/Raikou1.png[/IMG] [IMG]http://s30.postimg.org/abae0o0v5/Raikou2.png[/IMG] [IMG]http://s7.postimg.org/id2cyrsor/Raikou3.png[/IMG] [/SPOILER] ¡Toma, a la primera! ¡Nos ha salido un Raikou perfecto! Ahora se pueden sustituir los valores del pokémon que nos encontramos por los que nosotros queramos usando sólo "setvar". Ésa es la sección que viene a continuación. Bueno, el Raikou no es del todo perfecto... ¿Habéis notado ese trocito de vida que le falta? Eso es porque sólo he cambiado el pokémon que aparece, pero no la vida (¿os acordáis del 0076 que estaba marcado en verde? no es casualidad que 76 en HEX sea 118 en decimal). Por tanto, el pokémon tiene la misma vida que cuando era un Latias, y como Raikou tiene más vida máxima que Latias... ¿Entendéis? De momento no he encontrado una solución permanente para esto. He provado a ponerle una vida mayor que la máxima, pero lo que pasa es que si hieres al pokémon, durante un tiempo parecerá que no le restas vida... Lo único que se me ocurre es que si quieres poner X pokemon al nivel Y, busques en una calculadora de estadísticas la vida que debería de tener a ese nivel con valores iniciales al máximo, para asegurarte de que no te quedas corto, y así tampoco te pasas mucho de la vida máxima.[/SPOILER] Script del Pokémon Errante Hacer que aparezca un pokémon errante es tan simple como ejecutar un script. En Esmeralda el special 0x12B hace que aparezca un pokémon errante u otro dependiendo del valor que hay en la variable 0x8004: si es 0, aparece Latias, y si es 1 aparece Latios. En FR se usa el special 0x129 y la variable de entrada que utiliza es la 0x4031, que es donde se guarda el pokémon inicial que escogiste, y hace que aparezca Raikou, Entei o Suicune. Lo que vamos a hacer es llamar al special, hacer que aparezca uno de éstos pokemon como errante y sustituirlo por el pokemon que queramos. Los datos del pokémon errante se guardan en variables, así que conociendo estas variables podemos editar al pokémon errante como queramos. Concretamente, las variables son éstas: - Variable del pokémon: Esmeralda 0x4F24; RF 0x506C - Variable de la vitalidad: Esmeralda 0x4F25; RF 0x506D - Variable del nivel y estado: Esmeralda 0x4F26; RF 0x506E - Variable de la disponibilidad (0x100 = disponible, 0x0 = no disponible) = Esmeralda 0x5F29; FR 0x5071 Ahora explicaré qué significa cada variable y los pasos a seguir en Esmeralda, para Fire Red los pasos a seguir son idénticos. El script del pokémon es el siguiente: [SPOILER="ESMERALDA"]#org inicio special 0x12B setvar 0x4F24 0x'(nº del pokémon que quieras que sea errante) setvar 0x4F25 0x'(vitalidad del pokémon) setvar 0x4F26 0xXXYY'(YY es el nivel y XX es el estado) end[/SPOILER] [SPOILER="FIRE RED"]#org inicio special 0x129 setvar 0x506C 0x'(nº del pokémon que quieras que sea errante) setvar 0x506D 0x'(vitalidad del pokémon) setvar 0x506E 0xXXYY'(YY es el nivel y XX es el estado) end[/SPOILER] Voy a explicar para qué sirve cada variable: La primera indica el pokémon que nos aparecerá por la región. Por poner un ejemplo, yo quiero que me aparezca Raikou, cuyo número es F3, pues en mi caso pondré setvar 0x4F24 0xF3. La segunda determina la vida con la que nos encontramos al pokémon. Esto es muy importante, porque un valor muy alto provocaría que, al herir al pokémon, durante un tiempo su vida no decrezca (dependiendo de lo mucho que te hayas pasado de su vida máxima), y con un valor bajo te encontraías al pokémon con escasa vida. Para elegir un valor adecuado, podéis usar la siguiente calculadora [url=http://www.pokexperto.net/mecanica/javacalc.php] Pokéxperto; Calculadora DS/Advance de IV's & Stats[/url] Eliges el pokémon, su nivel, y a la derecha donde dice Resultados, en PS escribes 31, y pulsa "calcular stats" [SPOILER="Imagen"][IMG]http://s27.postimg.org/tyws0t35f/calculador.png[/IMG][/SPOILER] A mí me ha salido a la izquierda, en PS, 165. Pues paso este valor a hexadecimal (165 = A5 en HEX) y ya está. Lo que tengo que poner es setvar 0x4F25 0xA5. La tercera variable es complicada. En una misma variable se guarda el nivel y el estado (envenenamiento, parálisis...). El nivel es simple: escoge un nivel de 1 a 100 y lo pasas a hexadecimal. En mi caso quiero que salga al 50, que en HEX es 32, luego YY = 32. El estado es algo difícil; si no te interesa modificar el estado, ignora el siguiente spoiler y haz XX = 00. [SPOILER="Cambiar el estado (dormido, congelado, parálisis...)"]El XX es lo más difícil, establece el estado del pokémon. El estado se determina con la siguiente tabla, sacada de [url=http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_in_Generation_III]Pokémon data structure in Generation III - Bulbapedia, the community-driven Pokémon encyclopedia[/url] [SPOILER="Imagen"][IMG]http://s27.postimg.org/gg7yoxeer/Estado.png[/IMG][/SPOILER] Para poner un estado, escribe ocho ceros: 00000000 Esto es un número binario de ocho bits, donde cada uno puede tomar un valor entre 0 y 1. La tabla indica, para un número de 8 bits, qué estado aplica cada bit, leído de derecha a izquierda. Por ejemplo, este número 00001000 Tiene el cuarto bit igual a 1, y el resto 0. Según la tabla, el cuarto bit es envenenamiento, así que nuestro pokémon con este código estará envenenado (Notad que la tabla dice 3 para Poison, no 4, pero hay que tener en cuenta que empieza a contar desde 0, no desde 1). Si por ejemplo, aplicamos este código 00010000 El quinto bit indica quemado, es decir, nos encontraremos al pokémon quemado. También podemos mezclar algunos estados, por ejemplo: 01100000 Hará que el pokémon esté congelado, y cuando se descongele estará paralizado. El sueño ocupa 3 bits. Esto es porque además determina los turnos que quedan para que el pokémon se despierte. Por ejemplo, 001 en binario es 1, así que el próximo turno se despertará; 101 en binario es 5, así que dormirá durante 5 turnos, etc... Vale, muy bonito esto de los bits, pero… ¿cómo se aplica? Simple. Una vez que tengas tu código de 8 cifras en binario, lo pasas de binario a hexadecimal en la calculadora. Yo quiero que mi Raikou esté congelado. El código para congelamiento es 00100000, que en hexadecimal es 20. Por tanto, XX = 20. Entiendo que este procedimiento es bastante confuso. Si no te ha quedado claro y tienes alguna duda, deja tu pregunta en los comentarios ;) Nota: Si lo que tienes pensado es dormir o congelar al pokémon para que no se escape... Olvídate, porque se va a escapar igualmente. Y si no, que le pregunten a este pobre hombre ... (min 8:00) [url=http://www.youtube.com/watch?v=ZLnt-dTQ9lg]Pokémon FireRed - Episode 37 - Suicune - YouTube[/url][/SPOILER] La variable 0x4F29 indica si el pokémon está disponible (0x100 salvaje y vivo) o no (0x0 debilitado o capturado). Cuando llamas al "special" este valor es automáticamente 0x100, así que en principio no hace falta tocarlo. Lo que sí puede servir es para saber si ya hemos capturado o debilitado al pokémon (para interactuar con la historia de nuestro hack o cosas así). A modo de ejemplo, mi script queda de la siguiente forma: #org inicio special 0x12B setvar 0x4F24 0xF3 setvar 0x4F25 0xA5 setvar 0x4F26 0x2032 'o si no quieres poner ningún estado, simplemente 0x32 end Ejecutamos el script y... ... Vaya, parece que no ha pasado nada. Sin embargo, yo me he adelantado y antes programé un wildbattle contra Raikou para que me apareciera en la Pokédex. El resultado es el siguiente... [SPOILER="Imagen"] [IMG]http://s11.postimg.org/hgm0r9sgz/Raikou.png[/IMG] [/SPOILER] o.O [SPOILER="Imagen"][IMG]http://s29.postimg.org/zd5rjglyf/Raikou4.png[/IMG][/SPOILER] o.O o.O o.O o.O o.O ¡¡Funciona!! Bueno, si y no. Todavía queda investigar las zonas donde aparece, y poder hacer que aparezca más de un pokémon errante a la vez. Pero... yo diría que es un buen comienzo, ¿no te parece? :) Aquí dejo algunos ejemplos más, donde se ve que tampoco hace falta poner siempre la vida máxima al pokémon: [SPOILER="Imagen"][IMG]http://s30.postimg.org/qz1xqp84h/Entei.png[/IMG] [IMG]http://s15.postimg.org/g0wlqukm3/Caterpie.png[/IMG][/SPOILER] Editando la localización Para esta parte recomiendo que tengáis experiencia manejando editores hexadecimales. Cuando ejecutes el script de antes, el pokémon errante aparecerá por unos mapas específicos que están predefinidos en la ROM. Concretamente hay una tabla que indica las rutas por donde se mueve el poke: [SPOILER="ESMERALDA"]Offset 5D1A04: 19 1A 20 21 31 FF 1A 19 20 21 FF FF 20 1A 19 21 FF FF 21 20 19 1A 22 26 22 21 23 FF FF FF 23 22 24 FF FF FF 24 23 25 26 FF FF 25 24 26 FF FF FF 26 25 21 FF FF FF 27 24 28 29 FF FF 28 27 2A FF FF FF 29 27 2A FF FF FF 2A 28 29 2B FF FF 2B 2A 2C FF FF FF 2C 2B 2D FF FF FF 2D 2C 2E FF FF FF 2E 2D 2F FF FF FF 2F 2E 30 FF FF FF 30 2F 31 FF FF FF 31 30 19 FF FF FF[/SPOILER] [SPOILER="FIRE RED"]Offset 466C58: 13 14 27 29 FF FF FF 14 13 15 29 FF FF FF 15 14 16 FF FF FF FF 16 15 17 1B 2B FF FF 17 16 18 19 1A 1B 2B 18 17 19 1A 1D FF FF 19 17 18 1A 22 FF FF 1A 17 18 19 1C 1E FF 1B 16 17 1C 2B FF FF 1C 1A 1B 1E FF FF FF 1D 18 1E FF FF FF FF 1E 1C 1D 1F FF FF FF 1F 1E 20 FF FF FF FF 20 1F 21 FF FF FF FF 21 20 24 25 FF FF FF 22 19 23 FF FF FF FF 23 22 24 FF FF FF FF 24 21 23 25 FF FF FF 25 21 24 26 FF FF FF 26 25 27 FF FF FF FF 27 13 26 FF FF FF FF 29 13 14 2A FF FF FF 2A 29 14 FF FF FF FF 2B 16 17 1B FF FF FF 2C 2B 1B FF FF FF FF[/SPOILER] Cada fila de la tabla tiene la siguiente información: [LIST][*]Primer byte: nº de mapa en hex donde se encuentra el pokémon. [*]Resto de bytes: nº de mapa en hex donde estará el pokémon cuando cambiemos de mapa. [*]FF: todos los bytes que sean FF son ignorados. [/LIST] Además, nos encontramos con tres limitaciones: [LIST] [*]El nº de filas de la tabla indica el nº máximo de posibles localizaciones del pokémon. Por ejemplo, en esmeralda la tabla tiene 20 filas, así que el poke no podrá aparecer en más de 20 rutas. Ésta limitación se puede saltar. [*]El ancho de la tabla - 1 indica el nº máximo de rutas a las que puede estar conectada una ruta. En esmeralda cada fila tiene 6 bytes, pues como máximo una ruta podrá estar conectada a 6 - 1 = 5 posibles rutas. Ésta limitación no se puede saltar. [*]Cada fila tiene como mínimo 3 bytes distintos de FF. Es decir, cada ruta está conectada como mínimo con otras 2. Esto tiene una explicación curiosa, resulta que la rutina que calcula el área del pokemon errante está programada para que el poke no pueda aparecer donde tú estuviste hace 2 localizaciones. De esta forma se evita eso de alternar constantemente entre dos rutas hasta que aparezca el poke. Si un pokémon solo puede ir de una ruta a otra, y tu estuviste en esa ruta hace 2 mapas, el juego se queda pillado. Ésta limitación se puede saltar, pero requiere conocimientos de ASM y no lo recomiendo.[/LIST] Ya estamos en condiciones de editar la localización. Para editar esta tabla hará falta un editor hexadecimal, yo utilizo HxD. Primero debes tener una idea de las zonas donde se moverá el poke. Yo haré que el poke se mueva por este mapa (cortesía de Dani_SR_17): -Pueblo Paleta - Ruta 1 - Ciudad Verde - Ruta 2 ____ __ _ _ __- Ruta 3 - Abre Advance Map y apunta el nº de cada mapa, y conviértelos a hexadecimal con la calculadora de windows: Pueblo Paleta: 0 --> 0 Ciudad verde: 1 --> 1 Ruta 1: 19 --> 13 Ruta 2: 20 --> 14 Ruta 3: 21 --> 15 Ahora tenemos que hacer la tabla. Tenemos 5 localizaciones, así que la tabla tendrá 5 filas. No os preocupéis por el número de filas, podéis poner hasta 256 (LOL). Cada fila empieza con una localización, y los números siguientes son las localizaciones a las que se puede mover el poke. Mi tabla queda así: 00 13 01 13 14 13 00 01 15 14 01 15 13 Pero esta tabla puede hacer que el juego se trabe, porque hay filas con sólo 2 bytes y el mínimo es 3. En efecto, pueblo paleta y las rutas 2 y 3 sólo tienen una conexión, y el mínimo son 2 conexiones. Así que conectaré la ruta 2 con pueblo paleta y la ruta 3 con ciudad verde: 00 13 14 01 13 14 13 00 01 15 14 01 00 15 13 01 Rellena de FF hasta que cada fila tenga 7 bytes en FR, o hasta 6 bytes en esmeralda: 00 13 14 FF FF FF FF 01 13 14 FF FF FF FF 13 00 01 15 FF FF FF 14 01 00 FF FF FF FF 15 13 01 FF FF FF FF Ya tenemos nuestra tabla lista. Ahora abre la ROM con tu editor hexadecimal y ve al offset donde se encuentra la tabla. Si tu tabla es más corta que la tabla original (como es mi caso), simplemente pégala sobreescribiendo la tabla original, y rellena de FF hasta borrar por completo la tabla anterior. Si es más grande tendrás que buscar un espacio libre en la ROM terminado en 0, 4, 8, o C. El offset A00003 está vacío, pero no es válido porque termina en 3, pero el offset A00000 sí que nos sirve. Imaginemos que vas a pegar tu tabla en A00000. Ahora tendrás que hacer un repoint. Si usas HxD, ve a Buscar -> Reemplazar... Busca los pointers 58 6C 46 08 en FR, o 04 1A 5D 08 en esmeralda, y en reemplazar escribe el offset donde hayas puesto tu tabla, pero invertido: A00000 -> 00 00 A0 08. Tipo de datos: valores hexadecimales, Dirección Todo, y cuando esté todo listo Reemplazar todo. El último paso es decirle a la rutina la nueva longitud de la tabla. ¿Habéis visto que la tabla de FR mide 25 filas? 25 en hex es 19. Hay 3 bytes que indican el nº de filas de la tabla, aquí se indica la dirección donde se encuentran: [SPOILER="ESMERALDA"]En 161928: 14 En 1619c6: 14 En 161a82: 13[/SPOILER] [SPOILER="FIRE RED"]En 141d6e: 19 En 141df6: 19 En 141eae: 18[/SPOILER] La nueva longitud de la tabla es 5 filas, que en hex es 5 :D Así que cambiamos esos tres bytes por sus nuevos valores: En 141d6e: 05 En 141df6: 05 En 141eae: 04 Y listo, ya hemos definido los mapas por donde se mueve el pokemon errante. Hay que tener en cuenta que todos los números de mapa están referidos al banco 0 en esmeralda y al banco 3 en FR. Es decir, que nuestro poke sólo se podrá mover por los mapas del banco 0 en esmeralda y el banco 3 en FR. Si por algún motivo quieres que aparezca en un mapa fuera de ese banco (una cueva, una casa, la zona safari...) puedes ejecutar el siguiente script a la entrada del mapa: [SPOILER="ESMERALDA"]#org @inicio writebytetooffset 0x(banco del mapa) 0x203BC86 writebytetooffset 0x(nº de mapa) 0x203BC87 end[/SPOILER] [SPOILER="FIRE RED"]#org @inicio writebytetooffset 0x(banco del mapa) 0x203F3AE writebytetooffset 0x(nº de mapa) 0x203F3AF end[/SPOILER] Pero al cambiar de mapa el pokémon volverá a rondar por las rutas de la tabla. Varios Pokémon Errantes Con lo que se ha explicado hasta ahora sería bastante para hacer que aparezca el pokémon errante que quieras en el estado que quieras y donde quieras. Pero parece que hay una pequeña limitación... y es que el juego no está pensado para que aparezca más de un pokémon errante a la vez. Así que en principio hacer que aparezca más de un pokémon errante a la vez no es posible. Pero bueno, tampoco hace falta llevarse las manos a la cabeza. Lo que sí podemos hacer es elegir el pokémon que aparece en cualquier momento, con sólo ejecutar un script. Pondré un ejemplo: imagina que quieres que aparezcan un Lugia y un Ho-ho errantes por tu región, y que puedas elegir en cualquier momento cuál de los dos aparece. Primero tendrás que asignarle una flag a cada pokémon para establecer si ya se ha capturado o debilitado, en mi ejemplo la de Ho-ho es la 0x1100 y la de Lugia la 0x1101. Ahora puedes hacer que hayan dos personajes (o carteles, o lo que sea), de tal forma que el primero haga aparecer a Lugia y el segundo a Ho-ho. El script para el primero sería algo así: [SPOILER="Script"]#org @inicio lock faceplayer compare 0x4F24 0xFA 'Comprueba si el errante actual es Ho-ho if 0x1 goto Cambiarhohoporlugia 'Si lo es salta a esa línea compare 0x4F29 0x0 'Si el errante no es Ho-ho, entonces es Lugia. Esto comprueba si Lugia está disponible if 0x1 goto @capturado 'Si no está disponible, el hombre dice que está capturado msgbox @a 0x6 'Si está disponible, el hombre dice que está suelto release end #org Cambiarhohoporlugia checkflag 0x1101 'En esta flag está guardada la disponibilidad de Lugia if 0x1 goto @capturado 'Si es 1 ya lo hemos capturado (o debilitado :P) special 0x12B setvar 0x4F24 0xF9 'Lugia setvar 0x4F25 0xD7 'con 215 de vitalidad setvar 0x4F26 0x3C 'al nivel 60 msgbox @a 0x6 'El jipi nos dice que está disponible release end #org @capturado setflag 0x1101 msgbox @b 0x6 release end #org @a = Ahora mismo hay un LUGIA salvaje\nrondando por HOENN. #org @b = Parece que alguien ha capturado al\nLUGIA que merodeaba por HOENN.[/SPOILER] El script para el segundo sería parecido. Este script es simple y te permite tener dos pokémon errantes, de tal forma que el jugador elige cuál de los dos quiere capturar en cualquier momento. Desafortunadamente no guarda los datos de vitalidad y estado, así que cuando se cambie a Lugia por Ho-ho o viceversa volverán a tener la vida máxima y ningún problema de estado (es decir, se "curarán"). Esto tampoco es un gran problema, si quieres guardar la salud del pokémon tendrías que guardar su vitalidad y estado en dos variables con el comando "copyvar". Pero por ejemplo en mi hack ya hay 6 pokémon errantes diferentes, si quisiera que se guardaran el estado y vit. de cada pokémon me harían falta 12 variables, y los script serían eternos. Así que no guardar el estado el errante es mucho más fácil de hacer y además tampoco supone un gran problema. Si quieres que tus pokemon errantes aparezcan por rutas distintas, te recomiendo que uses el script que se explica al final de esta página. Así, puedes hacer que cada pokémon aparezca por rutas distintas. ¿Te ha parecido complicado? ¿No lo has entendido? ¿Se te ha ocurrido una idea pero no sabes cómo llevarla a cabo? Pues no te lo pienses y déjame un comentario, que estaré encantado de ayudarte :) FIN El humano (?) Para terminar, me gustaría aclarar que para los que uséis FR (que sereis la mayoría) hay un pequeño cabo suelto en mi investigación. Resulta que si buscáis en la pokédex el área del pokémon errante no aparecerá. Sin embargo sí que os saldrá el área de uno de los tres perros legendarios. De momento no he podido cambiar ese pequeño gran detalle, y me temo que no puedo asegurar que consiga arreglarlo... Si sois capaces de aceptar este defecto entonces no tendréis ningún problema. Aquí unas imágenes, donde se ve que aunque el área que aparece en la pokédex es la de Raikou, si lo buscamos nos encontramos al pokémon que hemos definido con la rutina: [SPOILER="Imágenes"][IMG]http://s27.postimg.org/61mf0idkz/Sin_t_tulo2.png[/IMG] [IMG]http://s30.postimg.org/9ti1gyk35/Sin_t_tulo3.png[/IMG] [IMG]http://s29.postimg.org/bbz6x0kw7/Sin_t_tulo.png[/IMG][/SPOILER] Y creo que nada mas... Espero haberte ayudado a hacer lo que querías en tu hack. Pero si no has conseguido lo que querías ya sabes, ¡¡coméntamelo!! Lo único que te pido a cambio es que si has seguido este tutorial me menciones en los créditos de tu hack (que aunque antes ya era chulo, ahora que has metido esto seguro que te ha quedado mejor :D) Gracias a todos los que os habéis tragado este tocho ;) Y sobre todo a esta comunidad, que aunque éste sea mi primer mensaje he aprendido todo lo que sé de RH gracias a todos los tutoriales, las preguntas y las respuestas que hacéis continuamente. Si os queda alguna duda, o veis algún fallo, mandadme un MP o comentadlo!! Un saludo!!!